import axios from 'axios';
import {AxiosCanceler} from './axiosCancel';
import {isFunction} from '@/utils/is';
import {cloneDeep} from 'lodash-es';
import {ContentTypeEnum} from './enum';


export class VAxios {
  constructor(options) {
    this.options = options;
    this.axiosInstance = axios.create(options);
    this.setupInterceptors();
  }


  createAxios(config) {
    this.axiosInstance = axios.create(config);
  }

  getTransform() {
    const {transform} = this.options;
    return transform;
  }

  getAxios() {
    return this.axiosInstance;
  }

  /**
   * @description: Reconfigure axios
   */
  configAxios(config) {
    if (!this.axiosInstance) {
      return;
    }
    this.createAxios(config);
  }

  /**
   * @description: Set general header
   */
  setHeader(headers) {
    if (!this.axiosInstance) {
      return;
    }
    Object.assign(this.axiosInstance.defaults.headers, headers);
  }

  /**
   * @description: Interceptor configuration
   */
  setupInterceptors() {
    const transform = this.getTransform();
    if (!transform) {
      return;
    }

    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform;


    const axiosCanceler = new AxiosCanceler();

    // Request interceptor configuration processing
    this.axiosInstance.interceptors.request.use((config) => {

      const {ignoreCancelToken} = config.requestOptions;
      const ignoreCancel =
        ignoreCancelToken !== undefined
          ? ignoreCancelToken
          : this.options.requestOptions.ignoreCancelToken;

      !ignoreCancel && axiosCanceler.addPending(config);
      if (requestInterceptors && isFunction(requestInterceptors)) {
        config = requestInterceptors(config, this.options);
      }

      return config;
    }, undefined);

    // Request interceptor error capture
    requestInterceptorsCatch &&
    isFunction(requestInterceptorsCatch) &&
    this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch);


    // Response result interceptor processing
    this.axiosInstance.interceptors.response.use(res => {
      res && axiosCanceler.removeAllPending(res.config);

      if (responseInterceptors && isFunction(responseInterceptors)) {
        res = responseInterceptors(res);
      }

      return res;
    }, undefined);


    // Response result interceptor error capture
    responseInterceptorsCatch &&
    isFunction(responseInterceptorsCatch) &&
    this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch);
  }

  // support form-data
  supportFormData(config) {
    const headers = config.headers || this.options.headers;
    const contentType = headers['Content-Type'] || headers['content-type'];


    if (
      contentType !== ContentTypeEnum.FORM_URLENCODED ||
      !Reflect.has(config, 'data') ||
      config.method.toUpperCase() === RequestEnum.GET
    ) {
      return config;
    }

    return {
      ...config,
      data: qs.stringify(config.data, {arrayFormat: 'brackets'}),
    };
  }

  get(config, options = {}) {
    return this.request({...config, method: 'GET'}, options);
  }

  post(config, options = {}) {
    return this.request({...config, method: 'POST'}, options);
  }

  put(config, options) {
    return this.request({...config, method: 'PUT'}, options);
  }

  delete(config, options) {
    return this.request({...config, method: 'DELETE'}, options);
  }


  request(config, options = {}) {
    let conf = cloneDeep(config);
    const transform = this.getTransform();

    const {requestOptions} = this.options;

    const opt = Object.assign({}, requestOptions, options);

    const {beforeRequestHook, requestCatchHook, transformRequestHook} = transform || {};
    if (beforeRequestHook && isFunction(beforeRequestHook)) {
      conf = beforeRequestHook(conf, opt);
    }
    conf.requestOptions = opt; //

    // conf = this.supportFormData(conf);

    return new Promise((resolve, reject) => {
      this.axiosInstance
        .request(conf)
        .then((res) => {
          console.log(res)
          if (transformRequestHook && isFunction(transformRequestHook)) {
            try {
              const ret = transformRequestHook(res, opt);
              resolve(ret);
            } catch (err) {
              reject(err || new Error(' 请求错误 '));
            }
            return;
          }
          resolve(res);
        })
        .catch((e) => {
          if (requestCatchHook && isFunction(requestCatchHook)) {
            reject(requestCatchHook(e, opt));
            return;
          }
          if (axios.isAxiosError(e)) {
            // 重写错误信息
          }
          reject(e);
        });
    });
  }
}
